package com.xayy.health.mgt.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.base.utils.annotation.DataTable;
import cn.kawins.mybatis.base.BaseServiceImpl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xayy.health.core.config.param.FaultParam;
import com.xayy.health.core.enums.LabelEnum;
import com.xayy.health.mgt.mapper.FaultInfoMapper;
import com.xayy.health.mgt.model.FaultInfo;
import com.xayy.health.mgt.model.dto.FaultInfoDto;
import com.xayy.health.mgt.model.vo.tupu.EquipmentResponseVo;
import com.xayy.health.mgt.model.vo.tupu.NodeVo;
import com.xayy.health.mgt.model.vo.tupu.RelationshipVo;
import com.xayy.health.mgt.service.FaultInfoService;
import com.xayy.health.mgt.service.SatelliteCodeService;
import org.apache.commons.collections4.list.TreeList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 故障信息表
 *
 * @author cuixidong
 * @version 1.0
 * @date 2023/4/6 13:54
 **/
@Service
public class FaultInfoServiceImpl extends BaseServiceImpl<FaultInfo> implements FaultInfoService {

    @Resource
    private FaultInfoMapper faultInfoMapper;

    @Autowired
    private FaultParam faultParam;

    @Autowired
    private SatelliteCodeService satelliteCodeService;

    /**
     * 分类统计故障信息
     *
     * @param faultInfoDto 入参信息
     * @return 故障信息
     */
    @Override
    public CheckResult<List<FaultInfo>> getFaultInfoList(FaultInfoDto faultInfoDto) {
        if (BeanUtil.isEmpty(faultInfoDto.getSatelliteId())) {
            return CheckResult.success();
        }
        Example example = new Example(FaultInfo.class);
        example.orderBy("diagnoseTime").desc();
        Example.Criteria criteria = example.createCriteria();
        if (BeanUtil.isNotEmpty(faultInfoDto.getSatelliteId())) {
            criteria.andEqualTo("satelliteId", faultInfoDto.getSatelliteId());
        }
        if (BeanUtil.isNotEmpty(faultInfoDto.getLevel()) && BeanUtil.isNotEmpty(faultInfoDto.getNodeId())) {
            Integer level = faultInfoDto.getLevel();
            switch (level) {
                case 1: {
                    criteria.andEqualTo("satelliteId", faultInfoDto.getNodeId());
                    break;
                }
                case 2: {
                    criteria.andEqualTo("systemId", faultInfoDto.getNodeId());
                    break;
                }
                default: {
                    criteria.andEqualTo("nodeId", faultInfoDto.getNodeId());
                    break;
                }
            }
        }
        if (BeanUtil.isNotEmpty(faultInfoDto.getSource())) {
            criteria.andEqualTo("source", faultInfoDto.getSource());
        }
        List<FaultInfo> faultInfos = selectByExample(example);
        return CheckResult.success(faultInfos);
    }

    /**
     * 引接第三方数据 入参信息
     * @return 结果日志信息
     */
    @Override
    public void leadFaultInfos() {
        Long  startTime=System.currentTimeMillis();
        String nowDateStr = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        StrBuilder url = new StrBuilder();
        url.append("\"").append("match p=(m:星)-[]-(n:分系统)-[]-(o:设备)-[]-(k:参数)-[]-(r:故障现象)-[]-(t:日期) where").append(" ").append("t.name<").append("'").append(nowDateStr).append("' ").append(faultParam.getCyphereEnd()).append("\"");
        log.info("leadFaultInfos 入参:" + url);
        HttpResponse execute = null;
        JSONObject jsonObject = null;
        try {
            // 调用第三方接口
            execute = HttpUtil.createRequest(Method.POST, faultParam.url + faultParam.id)
                    .header("Content-Type", "application/json")
                    .header("accesstoken", faultParam.accesstoken)
                    .body(url.toString(), "application/json")
                    .execute();
            if (!execute.isOk()) {
                log.error("接口调用失败,请检查入参及调用地址是否正确");
                return;
            }
            jsonObject = JSON.parseObject(execute.body());
        } catch (Exception e) {
            log.error("引接第三方数据leadFaultInfos异常",e);
            log.error("接口调用失败,请检查入参及调用地址是否正确");
            return;

        }

        log.info("-----------------------------");
        log.info("调用图谱接口返回结果为:" + jsonObject.toString());
        log.info("-----------------------------");
        Object data = jsonObject.get("data");
        List<FaultInfo> faultInfoList = new ArrayList<>();
        if (BeanUtil.isEmpty(data)) {
            log.error("卫星没有故障信息数据");
            return;
        }
        log.info("-----------------------------");
        log.info(data.toString());
        log.info("-----------------------------");
        EquipmentResponseVo responseVo = JSON.parseObject(data.toString(), EquipmentResponseVo.class);
        if (BeanUtil.isEmpty(responseVo)) {
            log.error("卫星没有故障信息数据");
            return ;
        }
        List<NodeVo> nodes = responseVo.getNodes();
        if (CollUtil.isNotEmpty(nodes)) {
            Map<String, List<NodeVo>> labelMap = nodes.stream().collect(Collectors.groupingBy(NodeVo::getLabel));
            Map<String, NodeVo> xingMap = nodeVoMap(labelMap, LabelEnum.XING.getName());
            Map<String, NodeVo> fxtMap = nodeVoMap(labelMap, LabelEnum.FXT.getName());
            Map<String, NodeVo> sbMap = nodeVoMap(labelMap, LabelEnum.SB.getName());
            Map<String, NodeVo> csMap = nodeVoMap(labelMap, LabelEnum.CS.getName());
            Map<String, NodeVo> rqMap = nodeVoMap(labelMap, LabelEnum.RQ.getName());

            List<RelationshipVo> relationships = responseVo.getRelationships();
            Map<String, List<RelationshipVo>> labelMap2 =
                    relationships.stream().collect(Collectors.groupingBy(RelationshipVo::getLabel));
            Map<String, RelationshipVo> gxCsMap = relationshipVoMap(labelMap2.get(LabelEnum.GX_CS.getName()), true);
            Map<String, RelationshipVo> gxRqMap = relationshipVoMap(labelMap2.get(LabelEnum.GX_RQ.getName()), true);
            Map<String, RelationshipVo> sbCsMap = relationshipVoMap(labelMap2.get(LabelEnum.SB_CS.getName()), false);
            Map<String, RelationshipVo> fxtSbMap = relationshipVoMap(labelMap2.get(LabelEnum.FXT_SB.getName()), false);
            Map<String, RelationshipVo> xFxtMap = relationshipVoMap(labelMap2.get(LabelEnum.XING_FXT.getName()), false);

            // 获取到故障现象节点列表
            List<NodeVo> nodeVos = labelMap.get(LabelEnum.GX.getName());
            for (NodeVo nodeVo : nodeVos) {
                FaultInfo faultInfo = new FaultInfo();
                // 故障现象
                faultInfo.setDescription(nodeVo.getProperties().getName());
                faultInfo.setLeadId(nodeVo.getId());
                // 故障日期
                RelationshipVo relationshipVo = gxRqMap.get(nodeVo.getId());
                String time = rqMap.get(relationshipVo.getEnd()).getProperties().getName();
                String replace = time.replace("年", "-").replace("月", "-").replace("日", " 00:00:00");
                String pattern = "^(19|20)\\d{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\\s([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$";
                Matcher m = Pattern.compile(pattern).matcher(time);
                if (m.matches()) {
                    DateTime dateTime = DateUtil.parse(replace);
                    faultInfo.setDiagnoseTime(dateTime);
                } else {
                    continue;
                }
                // 故障参数
                RelationshipVo relationshipVo1 = gxCsMap.get(nodeVo.getId());
                NodeVo nodeVo1 = csMap.get(relationshipVo1.getEnd());
                faultInfo.setParamCode(nodeVo1.getProperties().getCsdh());
                faultInfo.setParamName(nodeVo1.getProperties().getName());
                // 故障设备
                RelationshipVo relationshipVo2 = sbCsMap.get(nodeVo1.getId());
                NodeVo nodeVo2 = sbMap.get(relationshipVo2.getStart());
                faultInfo.setNodeId(Long.valueOf(nodeVo2.getId()));
                faultInfo.setNodeName(nodeVo2.getProperties().getName());
                // 故障分系统
                RelationshipVo relationshipVo3 = fxtSbMap.get(nodeVo2.getId());
                NodeVo nodeVo3 = fxtMap.get(relationshipVo3.getStart());
                faultInfo.setSystemId(Long.valueOf(nodeVo3.getId()));
                faultInfo.setSystemName(nodeVo3.getProperties().getName());
                // 故障星
                RelationshipVo relationshipVo4 = xFxtMap.get(nodeVo3.getId());
                NodeVo nodeVo4 = xingMap.get(relationshipVo4.getStart());
                faultInfo.setSatelliteId(Long.valueOf(nodeVo4.getId()));
                faultInfo.setSatelliteCode(nodeVo4.getProperties().getCode());
                faultInfo.setSatelliteName(nodeVo4.getProperties().getName());
                // 基本信息
                faultInfo.setFaultLevel(3);
                faultInfo.setSource(5);
                faultInfoList.add(faultInfo);
            }

        }
        // 处理数据
//        List<FaultInfo> faultInfos = selectAll();
//        Set<String> leadIds = faultInfos.stream().map(FaultInfo::getLeadId).collect(Collectors.toSet());
//        List<FaultInfo> insertFaultList = faultInfoList.stream().filter(x -> !leadIds.contains(x.getLeadId())).collect(Collectors.toList());
        Example example=new Example(FaultInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIsNotNull("id");
        deleteByExample(example);
        insertList(faultInfoList);
        log.info("故障信息插入总时间为：time={}",System.currentTimeMillis()-startTime);
        log.info("故障信息插入成功");
    }

    /**
     * 处理返回nodeVoMap
     *
     * @param labelMap 入参
     * @param label    入参
     * @return Map<String, NodeVo>
     */
    public Map<String, NodeVo> nodeVoMap(Map<String, List<NodeVo>> labelMap, String label) {
        List<NodeVo> nodeVoList = labelMap.get(label);
        Map<String, NodeVo> nodeVoMap = new HashMap<>(2);
        for (NodeVo nodeVo : nodeVoList) {
            nodeVoMap.put(nodeVo.getId(), nodeVo);
        }
        return nodeVoMap;
    }

    /**
     * 处理数据关系
     *
     * @param relationshipVoList 入参
     * @param isStart            入参
     * @return Map<String, RelationshipVo>
     */
    public Map<String, RelationshipVo> relationshipVoMap(List<RelationshipVo> relationshipVoList, Boolean isStart) {
        Map<String, RelationshipVo> relationshipVoMap = new HashMap<>(2);
        for (RelationshipVo relationshipVo : relationshipVoList) {
            String key;
            if (Boolean.TRUE.equals(isStart)) {
                key = relationshipVo.getStart();
            } else {
                key = relationshipVo.getEnd();
            }
            relationshipVoMap.put(key, relationshipVo);
        }
        return relationshipVoMap;
    }

    /**
     * 故障次数等级统计图
     * @param faultInfoDto 入参信息
     * @return 结果日志
     */
    @Override
    public CheckResult<?> statisticsFaultInfo(FaultInfoDto faultInfoDto) {
        if (BeanUtil.isEmpty(faultInfoDto.getSatelliteId())) {
            return CheckResult.success();
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<Object> level1 = new TreeList<>();
        List<Object> level2 = new TreeList<>();
        List<Object> level3 = new TreeList<>();
        List<Object> level4 = new TreeList<>();
        List<FaultInfo> faultInfos = getFaultInfoList(faultInfoDto).getData();
        Map<Date, List<FaultInfo>> datas =
                faultInfos.stream().collect(Collectors.groupingBy(FaultInfo::getDiagnoseTime));
        Set<Date> times = datas.keySet();
        TreeSet<Date> dates = new TreeSet<>(Date::compareTo);
        dates.addAll(times);
        dates.forEach(time -> {
            String format = simpleDateFormat.format(time);
            List<FaultInfo> timeFaults = datas.get(time);
            Map<Integer, Long> counts =
                    timeFaults.stream().collect(Collectors.groupingBy(FaultInfo::getFaultLevel, Collectors.counting()));
            List<Object> data1 = new ArrayList<>();
            data1.add(format);
            data1.add(counts.get(1) == null ? 0 : counts.get(1));
            level1.add(data1);
            List<Object> data2 = new ArrayList<>();
            data2.add(format);
            data2.add(counts.get(2) == null ? 0 : counts.get(2));
            level2.add(data2);
            List<Object> data3 = new ArrayList<>();
            data3.add(format);
            data3.add(counts.get(3) == null ? 0 : counts.get(3));
            level3.add(data3);
            List<Object> data4 = new ArrayList<>();
            data4.add(format);
            data4.add(counts.get(4) == null ? 0 : counts.get(4));
            level4.add(data4);
        });
        Map<String, Object> result = new HashMap<>(5);
        result.put("times", dates);
        result.put("level1", level1);
        result.put("level2", level2);
        result.put("level3", level3);
        result.put("level4", level4);
        return CheckResult.success(result);
    }

    /**
     * 获取故障信息分页列表
     * @return ResultBody
     */
    @DataTable(value = "faultPageList")
    public List<FaultInfo> faultPageList(Map<String, Object> params) {
        Object name = params.get("name");
        Example example = new Example(FaultInfo.class);
        example.orderBy("diagnoseTime").desc();
        Example.Criteria criteria = example.createCriteria();
        if (BeanUtil.isNotEmpty(name) && name != null) {
            String nameString = name.toString();
            nameString = "%" + nameString + "%";
            criteria.orLike("satelliteName", nameString);
            criteria.orLike("paramCode", nameString);
            criteria.orLike("description", nameString);
        }

        return selectByExample(example);
    }

    /**
     * 修改故障信息
     * @param faultInfo  故障信息
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> updateFaultInfo(FaultInfo faultInfo) {
        updateByIdSelective(faultInfo);
        return CheckResult.success();
    }

    /**
     * 故障评分获取部件近一年故障信息列表
     * @param satId 卫星id
     * @param nodeId 节点id
     * @param endTime 结束时间
     * @return 故障信息集合
     */
    @Override
    public CheckResult<List<FaultInfo>> selectByArgs(Long satId, Long nodeId, Date endTime, Date startTime) {
        Example example = new Example(FaultInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("satelliteId", satId);
        criteria.andEqualTo("nodeId", nodeId);
        criteria.andLessThanOrEqualTo("diagnoseTime", endTime);
        if(null!= startTime){
            criteria.andGreaterThanOrEqualTo("diagnoseTime",startTime);

        }
        List<FaultInfo> faultInfos = selectByExample(example);
        return CheckResult.success(faultInfos);
    }
}
